---
title: Dark Mode 

description: Customizing the theme in gluestack-ui v2 for different color schemes and color mode support.

showHeader: true
---

import { Canvas, Meta, Story } from '@storybook/addon-docs';

<Meta title="with-nativewind/Home/Theme Configuration/Dark Mode" />

import { Tabs } from '@gluestack/design-system';
import { CollapsibleCode } from '@gluestack/design-system';


## Color Scheme

gluestack-ui provides two ways of switching the color scheme or color mode: using CSS variables and using the `dark:` className support with `nativewind`.

### Using CSS Variables

With CSS variables, you can configure multiple color schemes in the `config.ts` file. This file contains two predefined color schemes: `light` and `dark`. It utilizes the [vars](https://www.nativewind.dev/v4/api/vars) functionality from nativewind to switch token values when the color mode is changed. This approach results in less code and makes configuring tokens for different color schemes easier.

### Usage

Let's look at an example where we define the `primary` token and switch it.

1. First, define the color token in your `tailwind.config.js` file and assign a variable value as shown below, following Tailwind's recommendation for [using CSS variables in Tailwind](https://tailwindcss.com/docs/customizing-colors#using-css-variables).

```js
// tailwind.config.js

module.exports = {
  theme: {
    extend: {
      colors: {
        primary: 'rgb(var(--color-primary)/<alpha-value>)'
      }
    }
  }
}
```

2. Now, define the values of that CSS variable for the `light` and `dark` color schemes in the `config.ts` file as shown below. [Reference](https://www.nativewind.dev/v4/guides/themes).

```js
// config.ts

export const config = {
  light: vars({
    '--color-primary': '51 51 51',
  }),
  dark: vars({
    '--color-primary': '240 240 240',
  })
}
```

3. Pass the color mode to the `GluestackUIProvider` using the `mode` prop and use the tokens inside your code. `mode`prop accepts three values: `system`, `light` and `dark`.

  - `system`: It uses the system color mode.
  - `light`: It uses the light color mode.
  - `dark`: It uses the dark color mode.

```js
// App.tsx

import { GluestackUIProvider } from "@/components/ui/gluestack-ui-provider";
import { Box } from "@/components/ui/box";
import { Button, ButtonText } from "@/components/ui/Button";
import { useState } from 'react';

export default function App() {
  const [colorMode, setColorMode] = useState<"light" | "dark">("light");

  return (
    <GluestackUIProvider mode={colorMode}>
      <Box className="bg-primary flex-1">
        <Button
          onPress={() => {
            setColorMode(colorMode === "light" ? "dark" : "light");
          }}
        >
          <ButtonText>Toggle color mode</ButtonText>
        </Button>
      </Box>
    </GluestackUIProvider>
  )
}
```

## Using Tailwind Dark Mode

gluestack-ui also supports Tailwind's default `dark:` concept. Let's see how to use it with an example.

```js
// App.tsx

import { GluestackUIProvider } from "@/components/ui/gluestack-ui-provider";
import { Box } from "@/components/ui/box";
import { Button, ButtonText } from "@/components/ui/Button";
import { useState } from 'react';

export default function App() {
  const [colorMode, setColorMode] = useState<"light" | "dark">("light");

  return (
    <GluestackUIProvider mode={colorMode}>
      <Box className="bg-white dark:bg-black flex-1">
        <Button
          onPress={() => {
            setColorMode(colorMode === "light" ? "dark" : "light");
          }}
        >
          <ButtonText>Toggle color mode</ButtonText>
        </Button>
      </Box>
    </GluestackUIProvider>
  )
}
```

In the above example, we switch the background color of our Box component in dark mode using the `dark:` syntax. To use dark mode, we need to change the `darkMode` strategy to `"class"` for the web and `"media"` for native devices in the `tailwind.config.js` file. You can achieve this by setting the `DARK_MODE` environment variable as shown below.

```js
// tailwind.config.js

module.exports = {
  darkMode: process.env.DARK_MODE ? process.env.DARK_MODE : 'media',
  // rest of the config
}
```

After this, we need to update our scripts in the `package.json` file as shown below:

```json
{
  "scripts": {
    "android": "DARK_MODE=media expo start --android",
    "ios": "DARK_MODE=media expo start --ios",
    "web": "DARK_MODE=class expo start --web"
  }
}
```

For Next.js projects, you can directly set the `darkMode` strategy to `"class"` without needing to change the scripts.

> Note: This is a temporary solution until we fix the issue with nativewind for the `darkMode:"class"` strategy.

## Persist Color Mode


<Tabs value="native" type="section">
  <Tabs.TabList>
      <Tabs.Tab value="native">
        <Tabs.TabTitle>Native</Tabs.TabTitle>
      </Tabs.Tab>
     <Tabs.Tab value="web">
        <Tabs.TabTitle>Web</Tabs.TabTitle>
     </Tabs.Tab>
  </Tabs.TabList>
  <Tabs.TabPanels>
    <Tabs.TabPanel value="native">
<>


Step 1: Install the following dependencies:
```bash
npm i @react-native-async-storage/async-storage
```

We will use the `@react-native-async-storage/async-storage` package to store the color mode in the device's local storage. You can also use other storage solutions.

Step 2: Create a new file `ThemeProvider.tsx` at `components/ui/ThemeProvider`.
<CollapsibleCode>

```jsx 
// components/ui/ThemeProvider/ThemeProvider.tsx
"use client";

import React, { createContext, useState, useEffect, useContext } from "react";
import AsyncStorage from "@react-native-async-storage/async-storage";

type Theme = "light" | "dark";

interface ThemeContextType {
  theme: Theme;
  toggleTheme: () => void;
}

export const ThemeContext = createContext<ThemeContextType | undefined>(
  undefined
);

export const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
  const [theme, setTheme] = useState<Theme>("light");

  useEffect(() => {
    (async () => {
      const savedTheme = (await AsyncStorage.getItem("theme")) as
        | Theme
        | "light";
      if (savedTheme) {
        setTheme(savedTheme);
        AsyncStorage.setItem("theme", savedTheme);
      }
    })();
  }, []);

  const toggleTheme = () => {
    const newTheme = theme === "light" ? "dark" : "light";
    setTheme(newTheme);
    AsyncStorage.setItem("theme", newTheme);
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

export const useTheme = () => {
  const context = useContext(ThemeContext);
  if (context === undefined) {
    throw new Error("useTheme must be used within a ThemeProvider");
  }
  return context;
};
```
</CollapsibleCode>

Step 3: Update your app's root to utilize the `ThemeProvider` component.

</>
    </Tabs.TabPanel>
    <Tabs.TabPanel value="web"> 
<>

Step 1: Install the following dependencies:
```bash
npm i js-cookie @types/js-cookie
```

We have to use the `js-cookie` library to set and get cookies in the browser.

Step 2: Create a new file `ThemeProvider.web.tsx` at `components/ui/ThemeProvider`.
<CollapsibleCode>

```jsx 
// components/ui/ThemeProvider/ThemeProvider.web.tsx
"use client";

import React, { createContext, useState, useEffect, useContext } from "react";
import Cookies from "js-cookie";

type Theme = "light" | "dark";

interface ThemeContextType {
  theme: Theme;
  toggleTheme: () => void;
}

export const ThemeContext = createContext<ThemeContextType | undefined>(
  undefined
);

export const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
  const [theme, setTheme] = useState<Theme>("light");

  useEffect(() => {
    const savedTheme = Cookies.get("theme") as Theme | undefined;
    if (savedTheme) {
      setTheme(savedTheme);
      document.documentElement.classList.add(savedTheme);
      document.documentElement.style.colorScheme = savedTheme;
    }
  }, []);

  const toggleTheme = () => {
    const newTheme = theme === "light" ? "dark" : "light";
    setTheme(newTheme);
    Cookies.set("theme", newTheme, { expires: 365 });
    document.documentElement.classList.remove(theme);
    document.documentElement.classList.add(newTheme);
    document.documentElement.style.colorScheme = newTheme;
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

export const useTheme = () => {
  const context = useContext(ThemeContext);
  if (context === undefined) {
    throw new Error("useTheme must be used within a ThemeProvider");
  }
  return context;
};
```
</CollapsibleCode>

Step 3: Update your app's root to utilize the `ThemeProvider` component.

</>
    </Tabs.TabPanel>
  </Tabs.TabPanels>
</Tabs>



Please refer to the Tailwind CSS dark mode [documentation](https://tailwindcss.com/docs/dark-mode) for more information and core concepts of dark mode.